#include <RSLib/Common.hpp>
#ifndef RSLIB___TIMINGS_HPP
#define RSLIB___TIMINGS_HPP
 
 
 
//---INCLUDE
//----------------------->
#include <RSLib/Types.hpp>
#ifdef RSLIB___WINDOWS
#include <RSLib/Windows.hpp>
#endif
#ifdef RSLIB___LINUX
#include <sys/time.h>
#endif
 
 
 
//---NAMESPACE
//--------------->
namespace RSLib {
 
 
 
#ifdef RSLIB___WINDOWS
 
#ifdef RSLIB___VC_COMPILER
#pragma comment(lib,"winmm.lib")	
#endif 
 
 
 
//---CLASS
//--------------------->
class LowResolutionTimer
{
public:
	typedef Void (*Callback)(Pointer);
	
public:
	LowResolutionTimer() : id(NULL){timeBeginPeriod(1);}
	~LowResolutionTimer(){timeEndPeriod(1);}
	
	
public:
	void Start(uint32 delay, Callback callback_, Pointer argument_, bool periodic = true)
	{
		callback = callback_;
		argument = argument_;
		
		id = timeSetEvent(delay, 0, TimeProc, DWORD_PTR(this), (periodic?TIME_PERIODIC:0) | TIME_CALLBACK_FUNCTION | TIME_KILL_SYNCHRONOUS);
		if (id == NULL) id = timeSetEvent(delay, 0, TimeProc, DWORD_PTR(this), (periodic?TIME_PERIODIC:0) | TIME_CALLBACK_FUNCTION);//TIME_KILL_SYNCHRONOUS not supported on OS<WinXP
		if (id == NULL) THROW_WIN32_MESSAGE("timeSetEvent failed!");
	}
	void Stop()
	{
		timeKillEvent(id);
		id = NULL;
	}
	bool IsActive(){return id != NULL;}
	bool IsntActive(){return id == NULL;}
	
private:
	static VOID CALLBACK TimeProc(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
	{
		LowResolutionTimer* timer = reinterpret_cast<LowResolutionTimer*>(dwUser);
		return timer->callback(timer->argument);
	}
	
private:
	UINT id;
	Callback callback;
	Pointer argument;
};
 
 
 
//---CLASS
//	Desc:	Wrapper to QueryPerformanceCounter
//----------------------------------------->
class HiResolutionClock
{
public:
	Unsigned64 count;
	
public:
	HiResolutionClock(){Start();}
	
public:
	Unsigned64 Start()
	{
		count = GetCounter();
		return count;
	}
	Unsigned64 Restart()
	{
		count = GetCounter();
		return count;
	}
	Unsigned64 GetElapsed()
	{
		return GetCounter() - count;
	}
	Float32 GetElapsedSeconds()
	{
		return Seconds( GetCounter() - count );
	}
	Unsigned64 GetElapsedAndRestart()
	{
		Unsigned64 newCount = GetCounter();
		Unsigned64 elapsed = newCount - count;
		count = newCount;
		
		return elapsed;
	}
	Float32 GetElapsedSecondsAndRestart()
	{
		Unsigned64 newCount = GetCounter();
		Unsigned64 elapsed = newCount - count;
		count = newCount;
		
		return Seconds(elapsed);
	}
	
	
public:
	static Unsigned64 GetFrequency()
	{
		Unsigned64 freq = 0;
		QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
		return freq;
	}
	static Unsigned64 GetCounter()
	{
		Unsigned64 counter = 0;
		QueryPerformanceCounter((LARGE_INTEGER*)&counter);
		return counter;
	}
	static Float32 Seconds(Unsigned64 value)
	{
		return Float32(value) / Float32(frequency);
	}
	
public:
	static Unsigned64 frequency;
};
 
__declspec(selectany) Unsigned64 HiResolutionClock::frequency = HiResolutionClock::GetFrequency();
 
 
 
 
//---CLASS
//	Desc:	Wrapper to timeGetTime
//-----------------------------------------> 
class LowResolutionClock
{
public:
	Unsigned32 count;
	
public:
	LowResolutionClock()
	{
		timeBeginPeriod(1);
		Start();
	}
	~LowResolutionClock()
	{
		timeEndPeriod(1);
	}
	
public:
	Unsigned32 Start()
	{
		count = GetCounter();
		return count;
	}
	Unsigned32 Restart()
	{
		count = GetCounter();
		return count;
	}
	Unsigned32 GetElapsed()
	{
		return GetCounter() - count;
	}
	Float32 GetElapsedSeconds()
	{
		return Seconds( GetCounter() - count );
	}
	Unsigned32 GetElapsedAndRestart()
	{
		Unsigned32 newCount = GetCounter();
		Unsigned32 elapsed = newCount - count;
		count = newCount;
		
		return elapsed;
	}
	Float32 GetElapsedSecondsAndRestart()
	{
		Unsigned32 newCount = GetCounter();
		Unsigned32 elapsed = newCount - count;
		count = newCount;
		
		return Seconds(elapsed);
	}
	
public:
	static Unsigned32 GetFrequency()
	{
		return frequency;
	}
	static Unsigned32 GetCounter()
	{
		return timeGetTime();
	}
	static Float32 Seconds(Unsigned32 value)
	{
		return Float32(value) / Float32(frequency);
	}
	
public:
	static Unsigned32 frequency;
};
 
__declspec(selectany) Unsigned32 LowResolutionClock::frequency = 1000;
 
 
 
//#endif defined(RSLIB___WINDOWS)
#elif defined(RSLIB___LINUX)
 
 
 
class HiResolutionClock
{
private:
	clock_t count;
	
public:
	HiResolutionClock(){Start();}
	
public:
Unsigned32 Start()
	{
		count = GetCounter();
		return count;
	}
	Unsigned32 Restart()
	{
		count = GetCounter();
		return count;
	}
	Unsigned32 GetElapsed()
	{
		return GetCounter() - count;
	}
	Float32 GetElapsedSeconds()
	{
		return Seconds( GetCounter() - count );
	}
	Unsigned32 GetElapsedAndRestart()
	{
		Unsigned32 newCount = GetCounter();
		Unsigned32 elapsed = newCount - count;
		count = newCount;
		
		return elapsed;
	}
	Float32 GetElapsedSecondsAndRestart()
	{
		Unsigned32 newCount = GetCounter();
		Unsigned32 elapsed = newCount - count;
		count = newCount;

		return Seconds(elapsed);
	}

public:
	static Unsigned32 GetFrequency()
	{
		return CLOCKS_PER_SEC;
	}
	static Unsigned32 GetCounter()
	{
		return clock();
	}
	static Float32 Seconds(Unsigned32 value)
	{
		return return Float32(value) / Float32( GetFrequency() );
	}
};
 
#endif//defined(RSLIB___LINUX)
 
 
 
}//namespace RSLib
 
 
 
#endif//RSLIB___TIMINGS_HPP
